#include <stdexcept> 
#include <Volume.h>
#include <Length.h>
#include <Unit.h>
#include <sstream>

Unit::Unit(int unit,UNIT_TYPE type):unit(unit),type(type)
{
}

int Unit::amountToBaseValue(const int amount) const
{
    return amount * unit;
}

int Unit::getAmount(int baseVlaue) const
{
    return baseVlaue / unit;
}

int Unit::getUnit() const
{
    return unit;
}

UNIT_TYPE Unit::getType() const
{
    return type;
}


UnitCalc::UnitCalc(int amount, const Unit& unit) : amount(amount), unit(unit)
{

}


bool UnitCalc::isSameType(const UnitCalc& unitCalc) const
{
    return (this->unit.getType() == unitCalc.unit.getType());
}

int UnitCalc::getBaseValue(const UnitCalc& unitCalc) const
{
    return unit.amountToBaseValue(unitCalc.amount);
}

int UnitCalc::toBaseValue(const UnitCalc& unitCalc) const
{
    return unit.amountToBaseValue(unitCalc.amount);
}


bool UnitCalc::operator==(const UnitCalc& unitCalc) const
{
    if(this->isSameType(unitCalc))
    {
     return this->getBaseValue(*this) == unitCalc.getBaseValue(unitCalc);	
    }	
    else
    {
     throw std::invalid_argument("Different Unit Type compare");
    }
}

bool UnitCalc::operator!=(const UnitCalc& unitCalc) const
{
    return !(*this == unitCalc);    
}

UnitCalc  UnitCalc::operator+(const UnitCalc& unitCalc) const
{ 
    int amount = 0;

    if(!this->isSameType(unitCalc))
    {
     throw std::invalid_argument("Different Unit Type ADD");
    }

    amount = this->unit.getAmount(this->toBaseValue(*this) 
					+ unitCalc.toBaseValue(unitCalc));

    return UnitCalc(amount, this->unit);
}


const int* UnitFactor[]= {
                          TIMES_LENGTH_UNIT,
                          TIMES_VOLUME_UNIT
                         };

const int UnitLength[]= {
                          LENGTH_OF_TIMES_LENGTH_UNIT,
                          LENGTH_OF_TIMES_VOLUME_UNIT
                         };

std::string *UnitList[]= {
                          LENGTH_UNIT_LIST,
                          VOLUME_UNIT_LIST
                          };


std::string UnitCalc::printInUnitFormat( ) const
{

    int NUM_OF_UNIT_OF_THE_TYPE = UnitLength[this->unit.getType()];
    int i;
    int value;
    int amountToBase = this->unit.amountToBaseValue(amount);

    std::stringstream  tmpString; 
      
    if (!amountToBase)
    {
     tmpString<<0<<" "<<UnitList[this->unit.getType()][NUM_OF_UNIT_OF_THE_TYPE-1];
     return tmpString.str();
    }

    for(i=0;i< NUM_OF_UNIT_OF_THE_TYPE;i++)
    {
     value = amountToBase/UnitFactor[this->unit.getType()][i];
     amountToBase = amountToBase%UnitFactor[this->unit.getType()][i];
     
     if(value)
     {
      if(amountToBase != 0)
      {
       tmpString<<value<<" "<<UnitList[this->unit.getType()][i]<<" ";
      }
      else
      {
       tmpString<<value<<" "<<UnitList[this->unit.getType()][i];
      }
     }
    }
    return tmpString.str();

}



std::string UnitCalc::printInMinUnitFormat( ) const
{

    int NUM_OF_UNIT_OF_THE_TYPE = UnitLength[this->unit.getType()];
    int amountToBase = this->unit.amountToBaseValue(amount);

    std::stringstream  tmpString; 
   
    tmpString<<amountToBase<<" "<<UnitList[this->unit.getType()][NUM_OF_UNIT_OF_THE_TYPE-1];

    return tmpString.str();

}


